package com.k8.rpc.directory;

import com.k8.common.factroy.BeanFactory;
import com.k8.rpc.invoke.Invoker;
import com.k8.rpc.metadata.AppMetaData;
import com.k8.rpc.url.URL;
import com.k8.rpc.util.RpcUtils;
import com.k8.rpc.util.URLUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class DynamicDirectory<T> implements Directory<T> {
    private final List<Invoker<T>> invokers;
    private final Map<Long, Invoker<T>> invokerMap;
    //用于映射服务接口name和具体接口
    private final Class<T> type;
    private final List<InvokerAddListener> invokerAddListeners = new LinkedList<>();
    private final BeanFactory beanFactory;

    public DynamicDirectory(List<Invoker<T>> invokerList, Map<Long, Invoker<T>> invokerMap, Class<T> type, BeanFactory beanFactory, URL url) {
        this.invokers = invokerList;
        this.invokerMap = new ConcurrentHashMap<>(invokerMap);
        this.type = type;
        this.beanFactory = beanFactory;
    }

    /**
     * 本方法对传入的实例对象的元数据信息和id进行检测,对目前存货的实例判断是否已经存在，不存在则新建
     * 若有实例已经不再存活，则进行标记
     * 若有实例重启，则标记存货
     */
    public void judgeInstanceIsAliveAndCreateNew(Map<Long, AppMetaData> idMaps, URL protocolUrl) {
        Set<Long> instanceIds = idMaps.keySet();
        Set<Long> ids = invokerMap.keySet();
        HashSet<Long> tempIds = new HashSet<>(ids);
        HashSet<Long> tempNewIds = new HashSet<>(instanceIds);
        for (Long instanceId : instanceIds) {
            if (tempIds.contains(instanceId)) {
                Invoker<T> invoker = invokerMap.get(instanceId);
                if (!invoker.isAvailable()) {
                    invoker.setAvailable(true);
                }
                tempIds.remove(instanceId);
                tempNewIds.remove(instanceId);
            }
        }
        //tempIds中即为失效的实例，而tempNewIds则为新的实例
        for (Long tempId : tempIds) {
            Invoker<T> invoker = invokerMap.get(tempId);
            if (invoker == null) {
                log.warn("Invoker is null , invokerId:{}", String.valueOf(tempId));
            } else {
                invoker.setAvailable(false);
            }
        }
        List<Invoker<?>> invokerList = new LinkedList<>();
        for (Long tempNewId : tempNewIds) {
            //处理方式要和AbsRegistryProtocol同步
            AppMetaData appMetaData = idMaps.get(tempNewId);
            URL serviceInstanceUrl = URLUtils.appMetaData2Url(appMetaData, protocolUrl);
            Invoker<T> consumerInvoker = RpcUtils.buildConsumerInvoker(serviceInstanceUrl, beanFactory, type);
            invokerList.add(consumerInvoker);
            invokerMap.put(tempNewId, consumerInvoker);
        }
        for (InvokerAddListener invokerAddListener : invokerAddListeners) {
            invokerAddListener.invokerAdd(invokerList);
        }
    }

    @Override
    public List<Invoker<T>> list() {
        return this.invokers;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public void addInvokerAddListener(InvokerAddListener invokerAddListener) {
        this.invokerAddListeners.add(invokerAddListener);
    }

    @Override
    public void destroy() {
        //todo
    }

    @Override
    public Class<T> type() {
        return this.type;
    }
}
